home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / W3WIN.C < prev    next >
C/C++ Source or Header  |  1993-06-16  |  44KB  |  1,532 lines

  1. #ifdef MSW /** WHOLE FILE **/
  2.   
  3. /*
  4.     This is a quickie port of MG2a (MicroEMACS derived) to MsWindows 3.1. 
  5.     The original code ran under DOS to a bios interface
  6.     with direct hardware access to the keyboard and system clock. This
  7.     version and the following w3 files have been (mostly) hooked in underneath
  8.     the original code, which thankfully had most of the terminal io (screen
  9.     access) and keyboard input at a level distinct from the core editor. Not
  10.     every function is relegated to the absolute best .C file location (for
  11.     example, a system call is implemented inside w3win.c since it is, after
  12.     all, a WinExec call.... In addition, much bashing was done to make
  13.     this Emacs look more like GNU-Emacs (make/next-error functions), automatic
  14.     timed backups, timestamp checking, and a large assortment of functions
  15.     implemented to extend the editor and move it away from MicroEMACS to
  16.     GNU-emacs feel. It's a reasonable result given the amount of time spent. :)
  17.  
  18.     The goal was not to make emacs window-aware. Instead, the window specific
  19.     code was to act like a terminal. That is why the startup code (windows code)
  20.     executes first; to create a window, etc such that when EmaxMain is called,
  21.     the 'terminal' (ie window) exists. The input handling is done by creating
  22.     an internal queue at the 'terminal' level and emacs just reads chars from
  23.     the 'keyboard' buffer. Special window-specific things happen without core
  24.     code being aware (ie focus events, etc). Events which require a core code
  25.     response, like window resize, generate emacs recognizable keycodes (or
  26.     entire command strings) which the editor can get. Resize in specific 
  27.     generates redraw-display and the core code already did a terminal size 
  28.     query for that command. 
  29.  
  30.     Mouse events are funny; window specific code handles them as far as
  31.     determining double click, etc. But window level code only goes as far
  32.     as converting mouse events to emacs commands for left, right, up/down,
  33.     etc. In other words, emacs is now mouse-aware, but in an abstract way.
  34.     A wayward user can use the keyboard to send mouse actions, though not
  35.     easily. Only window level code can parse a mouse click/motion to rows
  36.     and columns that emacs needs. This is based on font, window size, etc. 
  37.     I'm considering making the DOS version support the mouse since most 
  38.     of the code is there; just a couple of things to hook to the mouse.
  39.     (Could also do the system clock for time, auto backups, etc but I don't
  40.     want to kill Windows and I have to figure out how to get the interrupt
  41.     w/o zapping Windows so gnu would run safely in a DOS window. Same
  42.     cavet goes with making DOS-gnu use XMS.)
  43.  
  44.     Things to make better: foremost is the desire of the core editor to
  45.     write a single character at a time; and the windows level implementation is
  46.     being faithful to that request BUT it really should cache some consecutive
  47.     characters when it can! (DONE!) Next would be a cleanup of the ifdef's, and 
  48.     re-org of function-to-file mapping.
  49.  
  50.     w3 source files:
  51.  
  52.     jam.h                   version defines, includes, etc 
  53.     w3win.c (this file)     main, event loop, window proc, window creation, etc
  54.     w3io.c  (aka ttyio.c)   character output, scrolling, etc
  55.     w3key.c                 map keypress event to some EMACS virtual key for
  56.                               extended commands
  57.     w3font.c                support for fonts, emax.ini file support
  58.     w3mem.c                 32 bit global memory mangler
  59.     w3ext.c                 support for drag&drop, print, cut/copy/paste (to
  60.                               Window's clipboard)
  61.     dos.c                   not windows really, but new dos things
  62. */  
  63.  
  64. #define W3WIN_C         /* prevent multiple define of globals */
  65.  
  66. #include "jam.h"
  67. #include "windowsx.h"    /* windows/nt extension macros */
  68. #include "def.h"
  69. #include "keyname.h"
  70. #include "stdio.h"
  71. #include "ttydef.h"
  72. #include "chrdef.h"
  73. #include "malloc.h"
  74. #include "time.h" 
  75. #include "commdlg.h"     /* font and open/save file dialogs */
  76. #include "shellapi.h"    /* drag & drop */
  77.   
  78. extern void FAR _cdecl exit(int);    /* to keep compiler happy */
  79.  
  80. /* Globals, externed in jam.h
  81.  */
  82. HANDLE   g_hInstance;
  83. HWND     g_hWnd = 0;           /* the 1 and only window */
  84. HDC      g_hDC;
  85. int      g_nLineHeight, g_nCharWidth;
  86. UINT     g_idTimer = 0;
  87. int      g_caret_x = -1, g_caret_y = -1;
  88. HFONT    g_hfont = 0; 
  89. HFONT    g_oldFont = 0;
  90. BOOL     g_caret = FALSE;
  91. BOOL     g_update = FALSE;
  92. BOOL     edInited = FALSE;
  93. BOOL     g_hasFocus = FALSE;
  94. BOOL     g_menu = FALSE;
  95.  
  96. /* Misc contants
  97.  */
  98. #define FONT_CHOICE    100    /* menu ids for system menu */
  99. #define ABOUT_CHOICE    110
  100. #define SAVE_CHOICE     120
  101. #define TOGGLE_CHOICE   130
  102. #define ABORT_CHOICE    140
  103. #define COLORS_CHOICE   150
  104.  
  105. /* pullrights...
  106. */
  107. #define TCOLOR_CHOICE   200
  108. #define WCOLOR_CHOICE   210
  109. #define CCOLOR_CHOICE   220    /* changes color */
  110.  
  111. #define OPEN_CHOICE    300     /* menu ids for main window menu */
  112. #define OPEN_CHOICE2    310
  113. #define INSERT_CHOICE    320
  114. #define REVERT_CHOICE    330
  115. #define SAVEAS_CHOICE    340
  116. #define PRINT_CHOICE    350    
  117.  
  118. #define COPY_CHOICE    360     /* clipboard functions */
  119. #define CUT_CHOICE    370
  120. #define PASTE_CHOICE    380
  121.  
  122. #define HELP_APROPOS    390
  123. #define HELP_ABOUT      400
  124.  
  125. #define KEXTEND_CHOICE    500     /* menu ids for main window menu */
  126.  
  127. #define LEFT    0x1
  128. #define RIGHT    0x2
  129.  
  130. /* Local statics
  131.  */
  132. #ifdef WIN32
  133. # include <winbase.h>
  134.  static STARTUPINFO s_sInfo = { 0 };
  135.  static PROCESS_INFORMATION s_pInfo = { 0 };
  136. #else
  137.  static HWND s_appwindow = 0;
  138. #endif
  139. static int s_scrollTicks = 0;    /* autoscroll */
  140. static HCURSOR s_loadedcursor = 0;
  141. static BOOL s_waitingforapp = FALSE;
  142. static BOOL s_fatal = FALSE;
  143. static int s_btndown = 0;
  144. static int s_sleep = 0;
  145. static int s_sTicks = 0;          /* inc-save interval */
  146. static HRGN s_hrgn = 0;
  147. static char s_timestr[35] = {0};
  148. static char *s_APPNAMEQUESTION = AppQuestion;
  149. static char *s_APPNAMEMSG = AppMsg;
  150. static char *APPCLASS = "MyToy Class"; 
  151. static char *curname = 0;
  152. static char *blank = " ";
  153. static char s_spawnbuf[NFILEN];
  154.  
  155. /* Array of pulldown menus.
  156. */
  157. #define PARENT  0
  158. #define FILEM   1
  159. #define EDITM   2
  160. #define WINDOWM 3
  161. #define EXECM   4
  162. #define HELPM   5
  163. #define NUMBERM 6
  164.  
  165. #define FreeLoadedCursor(c)\
  166.   if (c)\
  167.     {\
  168.       DestroyCursor(c);\
  169.       c = 0;\
  170.     }
  171.  
  172. static HMENU s_menu[NUMBERM];
  173. static UINT s_choices = 0;
  174.  
  175. /* Local function prototypes
  176.  */
  177. BOOL FAR PASCAL findWindow(HWND hWnd, LONG lParam);
  178. static void SetTheTitle(void);
  179. static void WindowAddMenu(void);
  180. static void getthetime(void);
  181. static void DoMenuThing(void);
  182. static void chooseColor(WPARAM wParam);
  183. static void ReverseCaret(void);
  184.  
  185. BOOL WindowFatalState(void)
  186. {
  187.   return(s_fatal);
  188. }
  189. /* Set window title as appropriate.
  190.  */
  191. static void SetTheTitle()
  192. {
  193.   char buffer[200], dir[100];
  194.   static char lastTitle[200] = {0};
  195.  
  196.   strcpy(buffer, g_APPNAME);
  197.   strcat(buffer, " ");
  198.  
  199.   /* short vs long title
  200.   */
  201.   if (!IsIconic(g_hWnd) && wdir)
  202.     {
  203.       strcat(buffer, shortversion());
  204.       strcpy(dir, wdir);
  205.       adjustnamecase(dir);
  206.       strcat(buffer, "   (");
  207.       strcat(buffer, dir);
  208.       strcat(buffer, ") ");
  209.     }
  210.   
  211.   strcat(buffer, s_timestr);        /* update when needed */
  212.   if (strcmp(buffer, lastTitle) != 0)
  213.     {
  214.       SetWindowText(g_hWnd, buffer);
  215.       strcpy(lastTitle, buffer);        /* save last time */
  216.     }
  217. }
  218.  
  219. /* Update the time string, used for window title
  220.  */
  221. static void getthetime(void)
  222. {
  223.   long currtime;
  224.   struct tm *timestruct;
  225.   BOOL am = TRUE;
  226.   int hour;
  227.   
  228.   time(&currtime);
  229.   timestruct = localtime(&currtime);
  230.   hour = timestruct->tm_hour;
  231.   if (hour > 12)
  232.     {
  233.       hour -= 12;
  234.       am = FALSE;
  235.     }
  236.   sprintf(s_timestr, "  %d:%02d%s\0",
  237.           hour, timestruct->tm_min, am ? "am" : "pm");
  238. }
  239.  
  240. /*
  241.  * WinMain
  242.  *
  243.  * Arguments:
  244.  *
  245.  *       hInstance       - handle of this instance of notgnu.exe
  246.  *       hPrevInstance   - handle to a previous instance 
  247.  *       lpCmdLine       - string containing command line arguments
  248.  *       nCmdShow        - argument to ShowWindow that controls how
  249.  *                         Windows would like to start this application.
  250.  *
  251.  * Return value:
  252.  *  
  253.  *       an integer with the final result of the application
  254.  */
  255. int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
  256. HANDLE   hInstance;
  257. HANDLE   hPrevInstance;
  258. LPSTR    lpCmdLine;
  259. int      nCmdShow;
  260. {
  261.   int   argc = 0;
  262. #define NARGS 50
  263.   char *argv[50], *p;
  264.   WNDCLASS  wc;
  265.   char progname[NFILEN];
  266.   DWORD flags;
  267.   
  268.   /* who are we?  
  269.    */
  270.   if (!GetModuleFileName(hInstance, progname, NFILEN))
  271.     progname[0] = '\0';
  272.   
  273.   /* first thing to do is init the internal heap manager
  274.    * and the message queue
  275.    */
  276. #ifndef WIN32
  277.   W3memLocalInitialize();
  278.   
  279.   /* Set the max size of the message queue; default is 8.
  280.    */
  281.   {
  282.     int   queue_size = 300;
  283.     while (!SetMessageQueue(queue_size--))
  284.       ;
  285.   }
  286. #endif
  287.   
  288.   /*
  289.    * Move some of the arguments into global variables so that
  290.    * editor can use them later.
  291.    */
  292.   g_hInstance = hInstance;
  293.   
  294.   /*
  295.    * Set up argc and argv.
  296.    */
  297.   argv[argc++] = progname;
  298.   
  299.   p = lpCmdLine;
  300.  
  301.   /* Gather file names
  302.   */
  303.   if (argc >= NARGS)
  304.     {
  305. /*      printf("Number of input args too large! Truncating to %d\n", NARGS); */
  306.       argc = NARGS - 1;
  307.     }
  308.   while(p && *p)
  309.     {
  310.       while (*p && ISWHITE(*p))      /* get to start of this param */
  311.         p++;
  312.       argv[argc++] = p;
  313.       while (*p && !ISWHITE(*p))     /* get to end of this param */
  314.         p++;
  315.       
  316.       /* properly terminate it for 'main'
  317.        */
  318.       if (ISWHITE(*p))             /* more stuff may follow */
  319.         {
  320.           *p = '\0';
  321.           p++;
  322.         }
  323.     }
  324.   
  325.   /* Fill in window class structure with parameters that describe the    
  326.    * main window. Only need to do this if no previous task did it..
  327.    */
  328.   if (!hPrevInstance)
  329.     {
  330.       wc.style = CS_DBLCLKS;              /* Class style(s). */
  331.       wc.lpfnWndProc = MainWndProc;       /* Function to retrieve messages */
  332.       wc.cbClsExtra = 0;                  /* No per-class extra data.*/
  333.       wc.cbWndExtra = 0;                  /* No per-window extra data.*/
  334.       wc.hInstance = hInstance;           /* Application that owns the class.*/
  335.       wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  336.       wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
  337.       wc.lpszMenuName =  NULL; 
  338.       wc.hIcon = LoadIcon(hInstance, "ID_NOTICON");
  339.       wc.lpszClassName = APPCLASS;       /* Name used in call to CreateWindow. */
  340.       
  341.       /* Register the window class and check success/failure code. 
  342.        */  
  343.       if (!RegisterClass(&wc))
  344.         {
  345.           WindowMessage("Failed to create window class!", FALSE);
  346.           return(FALSE);
  347.         }
  348.     }
  349.   
  350.   /* create a window 
  351.    */
  352.   flags = WS_OVERLAPPEDWINDOW;
  353. #ifdef VBAR
  354.   flags |= WS_VSCROLL;
  355. #endif
  356.   g_hWnd = CreateWindow(APPCLASS, g_APPNAME, flags,
  357.                         CW_USEDEFAULT,    /* Default horizontal position.*/
  358.             CW_USEDEFAULT,    /* Default vertical position. */
  359.             CW_USEDEFAULT,    /* Default width. */
  360.             CW_USEDEFAULT,    /* Default height.*/
  361.             NULL,             /* Overlapped windows have no parent.*/
  362.             NULL,             /* Use the window class menu. */
  363.             hInstance, 
  364.             NULL              /* Pointer not needed. */
  365.             );
  366.   
  367.   /* If window could not be created, return "failure" 
  368.    */
  369.   if (!g_hWnd)
  370.     {
  371.       WindowMessage("Failed to create window!", FALSE); 
  372.       return(FALSE);
  373.     }
  374.   
  375.   /* Init internal input buffer(s)
  376.    */
  377.   InitInput();
  378.   
  379.   /* Grab the hdc, get a default font 
  380.    */  
  381.   g_hDC = GetDC(g_hWnd);  
  382.   SetBkMode(g_hDC, OPAQUE);
  383.   WindowInitFont(FONTSIZE);
  384.   
  385.   /* Size window based on font, find menubar setting
  386.    */
  387.   InitWindow(START_COLS, START_LINES);
  388.   UpdateWindow(g_hWnd);
  389.   
  390.   /* Make the window visible; update its client area 
  391.    * and add things to default system menu
  392.    */
  393.   ShowWindow(g_hWnd, nCmdShow); 
  394.   ttresize();
  395.   s_menu[PARENT] = (HMENU)0;
  396.   WindowAddMenu();
  397.   DragAcceptFiles(g_hWnd, TRUE); /* allow some drag/drop stuff */
  398.   
  399.   /*
  400.    * Call 'main' body of editor
  401.    */
  402.   edInited = TRUE;        /* any message after this is ok to process */
  403.   if (newUser())
  404.     MakeBanner();
  405.   EmaxMain(argc, argv);        /* return from here is exit editor */
  406.    
  407.   /* Free resources
  408.    */ 
  409.   if (g_idTimer)
  410.     KillTimer(g_hWnd, g_idTimer);        /* Stops the timer */
  411.   if (g_hfont)
  412.     {
  413.       SelectObject(g_hDC, g_oldFont);
  414.       DeleteObject(g_hfont);
  415.     }
  416.   ReleaseDC(g_hWnd, g_hDC);  
  417.   if (s_menu[0])
  418.     {
  419.       SetMenu(g_hWnd, 0);
  420.       DestroyMenu(s_menu[0]); 
  421.     }
  422.   DestroyWindow(g_hWnd);
  423.   
  424.   /* Cleanup the heap. Any memory not free-ed gets released
  425.    * since part of managed heap.
  426.    */
  427. #ifndef WIN32
  428.   W3memLocalTerminate();
  429. #endif
  430.   return 1;
  431. }
  432.  
  433. /* Pending event during screen refresh?
  434.  */
  435. BOOL WindowLookaheadEvent(void)
  436. {
  437.   MSG msg;
  438.   
  439.   if (PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
  440.     return(TRUE);
  441.   if (PeekMessage(&msg, NULL, WM_SIZE, WM_SIZE, PM_NOREMOVE))
  442.     return(TRUE);
  443.   
  444.   return(FALSE);
  445. }
  446.  
  447. /* Return a cached event; wait if none pending.
  448.  */
  449. void WindowGetEvent(void *ptr)
  450. {  
  451.   MSG  msg;
  452.   BOOL result;
  453.   
  454.   /* Make sure something is there
  455.    */
  456.   for (result = FALSE; !result; )
  457.     if (!(result = WindowReturnKCHAR((KCHAR *)ptr)))
  458.       {
  459.         /* See if Windows has any; process and return if
  460.          * result of Windows event yields a KCHAR, or if
  461.          * other KCHARs were waiting.
  462.          *
  463.          * Cursor on during wait...
  464.          */ 
  465.         if (IsCaretCreated() && (s_btndown == 0))
  466.          SetCaretVis(TRUE);
  467.   
  468.         if (GetMessage(&msg, NULL, NULL, NULL))
  469.       {
  470.             /* Cursor off during processing
  471.             */
  472.             if (IsCaretCreated())
  473.               SetCaretVis(FALSE);
  474.  
  475.         TranslateMessage(&msg);
  476.         DispatchMessage(&msg);
  477.       }
  478.       }
  479. }
  480.  
  481. /* Dump a string to a message box. If fatal,
  482.  * leave ungracefully...
  483.  */
  484. void WindowMessage(s, fatal)
  485. char *s;
  486. BOOL fatal;
  487. {
  488.   BOOL wasVis;
  489.  
  490.   if (wasVis = IsCaretVis())
  491.     SetCaretVis(FALSE);
  492.   MessageBox(0, s, s_APPNAMEMSG, MB_OK | MB_APPLMODAL);
  493.   if (wasVis)
  494.     SetCaretVis(TRUE);
  495.   if (fatal)
  496.     {
  497.       s_fatal = TRUE;
  498.       ealtmsg = TRUE;
  499.       IncrementalSave();
  500.       exit(1);
  501.     }
  502. }
  503.  
  504. /* Simple-minded stub to exec something 
  505.  */
  506. int winspawn(char *s, BOOL windows)
  507. {
  508.   char buf[NLINE];
  509.   BOOL sync;
  510. #ifdef WIN32
  511.   char *sh = "cmd.exe";
  512. #else
  513.   char *sh = "command.com";
  514.   FARPROC proc;
  515.   int appHandle;
  516. #endif
  517.   sync = FALSE;
  518.   
  519.   /* From 'shell-window' command (create a shell window)
  520.    */
  521.   if (!s)        /* lack of command string implies shell window */
  522.     {
  523. #ifdef WIN32
  524.       strcpy(buf, sh);
  525. #else
  526.       strcpy(buf, apppath());
  527.       strcat(buf, "meshell.pif");
  528.       if (!fileisok(buf))        /* is 'our' shell here? */
  529.         strcpy(buf, sh);        /* default shell */
  530. #endif
  531.     }
  532.   
  533.   /* From 'shell-command' or 'window-command' (spawn background job)
  534.    */
  535.   else if (s_waitingforapp && !windows)
  536.     {
  537.       /* Feeble - should be able to spawn multiple background
  538.       * processes, but I'm not managing multiple logs...
  539.       */
  540.       ewprintf("Pending shell-command already running in background.");
  541.       return (FALSE);
  542.     }
  543.  
  544.   /* build command string
  545.   */
  546.   else
  547.     {
  548.       if (windows)
  549.         strcpy(buf, s);
  550.       else
  551.         {
  552.           /* destroy log first so won't read old log by accident
  553.           */
  554.           strcpy(buf, dirpath());
  555.           strcat(buf, spawnfilename);
  556.           unlink(buf);
  557.  
  558.           strcpy(buf, sh);  
  559.           strcat(buf, " /c ");
  560.           strcat(buf, s);
  561.           strcat(buf, " > ");
  562.           strcat(buf, spawnfilename);
  563.           sync = TRUE;
  564.     
  565.           /* create name for reading in after
  566.           * task completes
  567.           */
  568.           strcpy(s_spawnbuf, dirpath());
  569.           strcat(s_spawnbuf, spawnfilename);
  570.         }
  571.     }
  572.   
  573. #ifdef WIN32
  574.     ewprintf("CreateProcess: %s", buf);
  575.     s_sInfo.cb = sizeof(STARTUPINFO);
  576.     s_sInfo.lpTitle = AppJob;
  577.     s_sInfo.wShowWindow = (sync ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL);
  578.     s_sInfo.dwFlags = STARTF_USESHOWWINDOW;
  579.  
  580.     if (CreateProcess(NULL, buf, NULL, NULL, DETACHED_PROCESS, 
  581.         FALSE, NULL, NULL, &s_sInfo, &s_pInfo)) 
  582.       {
  583.         if (sync)
  584.           s_waitingforapp = TRUE;
  585.       }
  586.     else
  587.       {
  588.         sprintf(buf, "CreateProcess error: %s", buf);
  589.         WindowMessage(buf, FALSE);
  590.         ewprintf(blank);
  591.         noop();
  592.         return (FALSE);
  593.       }
  594. #else
  595.   ewprintf("WinExec: %s", buf);
  596.   SetCaretVis(FALSE);
  597.   appHandle = WinExec(buf, sync ? SW_SHOWMINNOACTIVE : SW_SHOW);
  598.   if (appHandle < 32)  /* error */
  599.     {
  600.       sprintf(buf, "WinExec error %d", appHandle);
  601.       WindowMessage(buf, FALSE);
  602.       ewprintf(blank);
  603.       noop();
  604.       return (FALSE);
  605.     }
  606.   else if (sync)
  607.     {
  608.       /* job running, find window handle to wait for completion
  609.       */
  610.       proc = MakeProcInstance((FARPROC)findWindow, g_hInstance);
  611.       EnumWindows(proc, (DWORD)appHandle);
  612.       FreeProcInstance(proc);
  613.       
  614.       if (s_appwindow != 0) 
  615.         s_waitingforapp = TRUE;
  616.     }
  617. #endif
  618.   noop();
  619.   return(TRUE);
  620. }
  621.  
  622. /* 
  623.  * Main window procedure for the one and only window
  624.  * we create.
  625.  */
  626. long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
  627. HWND hWnd;
  628. UINT message;
  629. WPARAM wParam;
  630. LPARAM lParam;
  631. {
  632.   int status;
  633.   char buff[40];
  634.   int downcol, downrow; 
  635.   int cmd_param;
  636.   
  637.   switch (message) 
  638.     {      
  639.     case WM_CREATE:
  640.       g_idTimer = SetTimer(hWnd, NULL, TIME_INC, (FARPROC) NULL);
  641.       break;
  642.       
  643.     case WM_DROPFILES:
  644.       HandleDroppedFiles((HANDLE)wParam);    /* w3ext.c */
  645.       break;
  646.       
  647.     case WM_TIMER:
  648.       if (edInited)
  649.         {
  650.           static int tTicks = 0;          /* title update interval */
  651.   
  652.           /* Any messages printed by routines called
  653.           * from a WM_TIMER message must not use standard 
  654.           * output method.
  655.           */
  656.           ealtmsg = TRUE;
  657.  
  658.           /* Counter for titlebar update; also use this increment to
  659.            * check for spawned shells
  660.            */
  661.           tTicks++;
  662.           if (tTicks > INCS_PER_UPDATE)
  663.             {
  664.               getthetime();     /* get current clock time */
  665.               SetTheTitle();    /* fix window title */ 
  666.               tTicks = 0;
  667.  
  668.               /* Spawned app running?
  669.                */
  670. #ifdef DOGRINDER
  671.               if (!s_btndown && s_waitingforapp)
  672.                   WindowGrinderCursor();
  673. #endif
  674. #ifdef WIN32
  675.               if (!isearching && !eprompting && !s_btndown && 
  676.                   (s_waitingforapp && 
  677.                    !(WaitForSingleObject(s_pInfo.hProcess, 0) == WAIT_TIMEOUT)))
  678.                 {
  679.                   CloseHandle(s_pInfo.hThread);
  680.                   CloseHandle(s_pInfo.hProcess);
  681. #else
  682.               if (!isearching && !eprompting && !s_btndown && 
  683.                   (s_waitingforapp && !IsWindow(s_appwindow)))
  684.                 {
  685. #endif
  686.                   s_waitingforapp = FALSE;
  687.                   ttbeep();
  688. #ifdef DOGRINDER
  689.                   WindowNormalCursor();
  690. #endif
  691.                   status = MessageBox(0, "Shell command completed, read log?",
  692.                       s_APPNAMEQUESTION, 
  693.                                       MB_YESNO | MB_APPLMODAL | MB_ICONQUESTION);
  694.               if (status == IDYES)
  695.             {
  696.                       BUFFER *bp = bfind(spawnfilename, FALSE);
  697.  
  698.                       /* Nuke any old logs from different dirs
  699.                       */
  700.                       if (bp)
  701.                         {
  702.                           bp->b_flag &= ~BFCHG;
  703.                           if (strcmp(bp->b_fname, s_spawnbuf) != 0)
  704.                             nukebuffer(bp);
  705.                         }                 
  706. #if 1
  707.                       ExtendedFunction(function_name(poptofilequiet));
  708.               AddString(s_spawnbuf);
  709.               AddKchar(CCHR('J'));
  710. #else   
  711.               AddString(s_spawnbuf);
  712.               AddKchar(CCHR('J'));
  713.                       poptofilequiet(0, 1);   /* go get it */
  714.                       ExtendedFunction(function_name(donothing));
  715.  
  716.                       /* Mark the file to be deleted when buffer is
  717.                       * nuked
  718.                       */
  719.                       if (bp = bfind(spawnfilename, FALSE))
  720.                         bp->b_flag |= BFDELETE;
  721. #endif
  722.                     }
  723.                 }
  724.   
  725.               /* Any user defined alarms to execute?
  726.               */
  727.                 {
  728.                   static BOOL incallback = FALSE;
  729.  
  730.                   if (!incallback)
  731.                     {
  732.                       incallback = TRUE;
  733.                       AnyPendingAlarms();
  734.                       incallback = FALSE;
  735.                     }
  736.                 }
  737.             } /* incs per update */
  738.  
  739.           /* Auto scroll current window if left button
  740.           * down and control key is also
  741.           */
  742.           if ((s_btndown & LEFT) && (GetKeyState(VK_CONTROL) < 0))
  743.             {
  744.               s_scrollTicks++;
  745.               if (s_scrollTicks >= DELAY_TO_SCROLL)
  746.                 {
  747.                   char buff[8];
  748.  
  749.                 ExtendedFunction(function_name(mousecmd)); 
  750.                   AddString(MouseTimer);
  751.                   sprintf(buff, " %d ", GetKeyState(VK_SHIFT) < 0 ? 1: 0);
  752.                   AddString(buff);
  753.                   s_scrollTicks = DELAY_TO_SCROLL;    /* prevent overflow */
  754.                 }
  755.             }
  756.           else
  757.             s_scrollTicks = 0;    /* force reset */
  758.  
  759.           /* Counter for incremental save (keyboard input delays this)
  760.           * and pending prompt postpones this indefinitly!!!
  761.           */
  762.           s_sTicks++;
  763.           if ((s_sTicks > INCS_PER_SAVE) && !eprompting)
  764.             {
  765.               static BOOL incallback = FALSE;
  766.  
  767.               if (!incallback)
  768.                 {
  769.                   incallback = TRUE;
  770.                   IncrementalSave();    /* autosave in file.c */
  771.                   incallback = FALSE;
  772.                   s_sTicks = 0;
  773.                 }
  774.             }
  775.           ealtmsg = FALSE;
  776.         }
  777.       break;
  778.       
  779.     case WM_SYSCOLORCHANGE:
  780.       return (0);        /* basically ignored. */
  781.  
  782.     case WM_SYSCOMMAND:
  783.       switch (wParam)
  784.         {
  785.       case FONT_CHOICE:
  786.         WindowNewFont();
  787.         break;
  788.       case ABOUT_CHOICE:
  789.         MakeBanner();
  790.         break;
  791.       case SAVE_CHOICE:
  792.         SaveAllSettings();
  793.         break;
  794.       case TOGGLE_CHOICE:
  795.         togglemenu(0, 1);
  796.         break;
  797.       case ABORT_CHOICE:
  798.         status = MessageBox(0, "Shoot me dead now?\n (This is equal to a crash!)", 
  799.                             s_APPNAMEQUESTION, MB_YESNO | MB_APPLMODAL | 
  800.                             MB_ICONSTOP);
  801.         if (status == IDYES)
  802.           ExtendedFunction(function_name(shootmedead));
  803.         break;
  804.  
  805.       case TCOLOR_CHOICE:
  806.       case WCOLOR_CHOICE:
  807.       case CCOLOR_CHOICE:
  808.         chooseColor(wParam);
  809.         break;
  810.       default:
  811.         return (DefWindowProc(hWnd, message, wParam, lParam));
  812.         }
  813.       break;
  814.       
  815.     case WM_SETFOCUS:
  816. #ifdef WINDOWS_CURSOR
  817.       CreateCaret(hWnd, NULL, g_nCharWidth, g_nLineHeight);
  818.       SetCaretPos(g_caret_x, g_caret_y);
  819. #endif
  820.       SetCaretCreated(TRUE);
  821.       g_hasFocus = TRUE;
  822.       break;
  823.       
  824.     case WM_KILLFOCUS:
  825.       SetCaretVis(FALSE);
  826. #ifdef WINDOWS_CURSOR
  827.       DestroyCaret();
  828. #endif
  829.       SetCaretCreated(FALSE);
  830.       g_hasFocus = FALSE;
  831.       break;
  832.       
  833. #ifdef VBAR        /* never completed, not 1/buffer, etc */
  834.     case WM_VSCROLL:
  835.       if (edInited)
  836.         switch(wParam)
  837.           {
  838.         case SB_TOP:
  839.           ExtendedFunction(function_name(gotobob));
  840.           break;
  841.         case SB_BOTTOM:
  842.           ExtendedFunction(function_name(gotoeob));
  843.           break;
  844.         case SB_LINEUP:
  845.           ExtendedFunction(function_name(back1page));
  846.           break;
  847.         case SB_LINEDOWN:
  848.           ExtendedFunction(function_name(forw1page));
  849.           break;
  850.         case SB_PAGEUP:
  851.           ExtendedFunction(function_name(backpage));
  852.           break;
  853.         case SB_PAGEDOWN:
  854.           ExtendedFunction(function_name(forwpage));
  855.           break;
  856.         default:
  857.           noop();
  858.           }
  859.       break;
  860. #endif
  861.       
  862.     case WM_RBUTTONDOWN:
  863.       GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
  864.       s_btndown |= RIGHT;
  865.       ExtendedFunction(function_name(mousecmd));
  866.       if (s_btndown & LEFT)
  867.         {
  868.           AddString(MouseAbort); 
  869.           AddKchar(' ');
  870.         }
  871.       else
  872.         {
  873.           AddString(RightDwn);
  874.           sprintf(buff, posFormat, downrow, downcol);
  875.           AddString(buff);
  876.         }
  877.       break;
  878.  
  879.     case WM_RBUTTONUP:
  880.       if (s_btndown & RIGHT)    /* was it down in our window?? */
  881.         s_btndown &= ~RIGHT;
  882.       noop();
  883.       break;
  884.  
  885.     case WM_MOUSEMOVE:
  886.       GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
  887.       if ((s_btndown & LEFT) && !(s_btndown & RIGHT))
  888.         {
  889.           s_scrollTicks = 0;    /* stop autoscroll */
  890.           ExtendedFunction(function_name(mousecmd));
  891.           AddString(MoveStr);
  892.           sprintf(buff, posFormat, downrow, downcol);
  893.           AddString(buff);
  894.         }
  895.       break;
  896.  
  897. #if 1                    /* there is a redraw marker bug :( */
  898.     case WM_MOUSEACTIVATE:
  899.       return (MA_ACTIVATEANDEAT);
  900. #endif
  901.  
  902.     case WM_LBUTTONDOWN:
  903.       GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
  904.       s_btndown |= LEFT;
  905.       ExtendedFunction(function_name(mousecmd));
  906.       if (s_btndown & RIGHT)
  907.         {
  908.           AddString(MouseAbort);
  909.           AddKchar(' ');
  910.         }
  911.       else
  912.         {
  913.           if (wParam & MK_SHIFT)
  914.             AddString(LeftDwnShift);
  915.           else
  916.             AddString(LeftDwn);
  917.           sprintf(buff, posFormat, downrow, downcol);
  918.           AddString(buff);
  919.           SetCapture(g_hWnd);
  920.         }
  921.       break;
  922.  
  923.     case WM_LBUTTONUP:
  924.       GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
  925.       if (s_btndown & LEFT)    /* was it down in our window?? */
  926.         {
  927.           s_btndown &= ~LEFT;
  928.           ExtendedFunction(function_name(mousecmd));
  929.           AddString(LeftUp);
  930.           sprintf(buff, posFormat, downrow, downcol);
  931.           AddString(buff);
  932.           ReleaseCapture();
  933.         }
  934.       break;
  935.  
  936.     case WM_LBUTTONDBLCLK:
  937.       GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
  938.       if ((s_btndown & RIGHT) == 0)
  939.         { 
  940.           ExtendedFunction(function_name(mousecmd));
  941.           AddString(DoubleClick);
  942.           AddKchar(' ');
  943.         }
  944.       else
  945.         {
  946.           AddString(MouseAbort);
  947.           AddKchar(' ');
  948.         }
  949.       ReleaseCapture();
  950.       break;
  951.  
  952.     case WM_COMMAND:
  953.       cmd_param = (int)LOWORD(wParam); 
  954.       if ((cmd_param >= KEXTEND_CHOICE) && (cmd_param <= (int)s_choices))
  955.         {
  956.           char cmd[NLINE + 1];
  957.           register int i;
  958.  
  959.           /* This hacky loop let me move menu items anywhere I 
  960.           * wanted w/o having to know which pulldown it belonged to (or
  961.           * care for that matter).  All 'extendable' functions have an
  962.           * id between KEXTEND_CHOICE and s_choices (s_choices is incremented
  963.           * after each moveable, extendable menu item is added). Ok, so it's
  964.           * a little ughly, but it was quick and easy!
  965.           */
  966.           for (i = 1; i <= NUMBERM; i++)
  967.             if (GetMenuString(s_menu[i], cmd_param, cmd, NLINE, 
  968.                   MF_BYCOMMAND) > 0)
  969.               {
  970.                 ExtendedFunction(cmd);
  971.                 break;
  972.               }
  973.          }
  974.       else  /* special case pre-processed events */
  975.         switch(cmd_param)
  976.           {
  977.         case HELP_APROPOS:
  978.           ExtendedFunction(function_name(apropos_command));
  979.           AddKchar('a');
  980.           AddKchar(CCHR('J'));
  981.           break;
  982.  
  983.         case HELP_ABOUT:
  984.           MakeBanner();
  985.           break;
  986.  
  987.         case COPY_CHOICE:
  988.         case CUT_CHOICE:
  989.           HandleCutCopy(cmd_param == CUT_CHOICE ? TRUE : FALSE);
  990.           break;
  991.  
  992.         case PASTE_CHOICE:    /* NOTE Not dimming choices yet! */
  993.           HandlePaste();
  994.           break;
  995.  
  996. #ifdef DOPRINT
  997.         case PRINT_CHOICE:
  998.           HandlePrint();
  999.           break;
  1000. #endif
  1001.  
  1002.         case OPEN_CHOICE:
  1003.         case INSERT_CHOICE:
  1004.         case OPEN_CHOICE2:
  1005.         case SAVEAS_CHOICE:
  1006.             {
  1007.               OPENFILENAME openfile;
  1008.               char fname[NFILEN+1];
  1009.               BOOL result = FALSE;
  1010.  
  1011.               memset(fname, '\0', sizeof(fname));
  1012.               memset(&openfile, '\0', sizeof(OPENFILENAME));
  1013.               strcpy(fname, "*.c;*.h;*.txt");
  1014.               openfile.lStructSize = sizeof(openfile);
  1015.               openfile.lpstrFilter = "*.*";
  1016.               openfile.lpstrFile = fname;
  1017.               openfile.nMaxFile = sizeof(fname);
  1018.               if (cmd_param == SAVEAS_CHOICE)
  1019.                 openfile.Flags = OFN_OVERWRITEPROMPT;
  1020.               openfile.Flags |= OFN_PATHMUSTEXIST;
  1021.               openfile.Flags |= OFN_HIDEREADONLY;
  1022.  
  1023.               EnableWindow(g_hWnd, FALSE);
  1024.               if (cmd_param == SAVEAS_CHOICE)
  1025.                 result = GetSaveFileName(&openfile);
  1026.               else
  1027.                 result = GetOpenFileName(&openfile);
  1028.               EnableWindow(g_hWnd, TRUE);
  1029.               SetActiveWindow(g_hWnd);
  1030.  
  1031.               if (result)
  1032.                 {
  1033.                   disable_preload();    /* full name already supplied */
  1034.                   if (cmd_param == OPEN_CHOICE)
  1035.                     ExtendedFunction(function_name(filevisit));
  1036.                   else if (cmd_param == OPEN_CHOICE2)
  1037.                     ExtendedFunction(function_name(poptofile));
  1038.                   else if (cmd_param == SAVEAS_CHOICE)
  1039.                     ExtendedFunction(function_name(filewrite));
  1040.                   else 
  1041.                     ExtendedFunction(function_name(fileinsert));
  1042.                   AddString(fname);
  1043.                   AddKchar(CCHR('J'));
  1044.                 }
  1045.             }
  1046.         default:
  1047.           break;
  1048.           }
  1049.       break;
  1050.  
  1051.     case WM_SYSKEYDOWN:
  1052.     case WM_SYSCHAR:
  1053.     case WM_CHAR:
  1054.     case WM_KEYDOWN:
  1055.       if (edInited)
  1056.         {
  1057.           /* SPECIAL CASE TO ALLOW TASK SWITCHING AND ACCESS
  1058.            * TO SYSTEM MENU
  1059.            */
  1060.           if ((message == WM_SYSKEYDOWN) && (wParam == VK_TAB))
  1061.             return (DefWindowProc(hWnd, message, wParam, lParam));
  1062.           if ((message == WM_SYSCHAR) && (wParam == ' '))
  1063.             return (DefWindowProc(hWnd, message, wParam, lParam));
  1064.   
  1065.           /* Regular input events cause some delay to autosave
  1066.            */
  1067.           s_sTicks -= SAVE_DELAY;
  1068.           if (s_sTicks < 0)
  1069.             s_sTicks = 0;
  1070.  
  1071.           /* Prevent garbled commands interrupting mouse
  1072.           */
  1073.           if (!s_btndown)
  1074.             WindowMapKey(message, wParam, lParam);
  1075.         }
  1076.       break;
  1077.       
  1078.     case WM_PAINT:
  1079.       {
  1080.         HDC hDC;
  1081.         PAINTSTRUCT ps;
  1082.         RECT r;
  1083.  
  1084.         /* satisfy windows, get the update region
  1085.          */
  1086.         hDC = BeginPaint (hWnd, &ps);
  1087.         r = ps.rcPaint;
  1088.         EndPaint(hWnd, &ps); 
  1089.  
  1090.         /* Draw...
  1091.          */
  1092.         if (!IsIconic(g_hWnd) && edInited)
  1093.           {
  1094.             int row = ttrow;
  1095.             int col = ttcol;
  1096.  
  1097.             sgarbf = TRUE;
  1098.             s_hrgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
  1099.             SelectClipRgn(g_hDC, s_hrgn);
  1100.  
  1101.             /* Fix in-progress stuff after redraw; in all cases
  1102.             * some event gets into the input queue to get the  
  1103.             * cursor updated after processing. Not pretty!
  1104.             */
  1105.             update();
  1106.             if (isearching)
  1107.               noop(); /* jumpSearch(); hacky research to refresh */
  1108.             else if (eprompting)
  1109.               erepair();         /* fix prompt+msg */
  1110.             else 
  1111.               ExtendedFunction(function_name(donothing));
  1112.             SelectClipRgn(g_hDC, NULL);
  1113.             DeleteObject(s_hrgn);  
  1114.             ttmove(row, col);     /* restore cursor */
  1115.           }
  1116.         break;
  1117.       }
  1118.       
  1119.     case WM_SIZE:
  1120.       if (!IsIconic(g_hWnd))
  1121.         {
  1122.           if (edInited)
  1123.             {
  1124.               RECT rect;
  1125.  
  1126.               GetClientRect(g_hWnd, &rect);
  1127.               ValidateRect(g_hWnd, &rect);
  1128.               ExtendedFunction(function_name(myrefresh));
  1129.             }
  1130.         }
  1131.       SetTheTitle();
  1132.       break;
  1133.       
  1134.     case WM_QUERYENDSESSION:
  1135.       if (!anycb(ABORT))
  1136.         {
  1137.           ExitCleanup();    /* cleanup work files */
  1138.           return(1);        /* all clear to exit */
  1139.         }
  1140.       
  1141.       /* Modified files, tell user and request dispostion (love them 
  1142.        * big words!)
  1143.        */
  1144.       ShowWindow(g_hWnd, SW_SHOW);
  1145.       status = MessageBox(0, "Saved modified buffers?", s_APPNAMEQUESTION, 
  1146.                           MB_YESNOCANCEL | MB_SYSTEMMODAL | MB_ICONQUESTION);
  1147.       if (status == IDNO)
  1148.         {
  1149.           ExitCleanup();    /* cleanup work files */
  1150.           return(1);        /* let windows go */
  1151.         }
  1152.       else if (status == IDYES)
  1153.         {
  1154.           savebuffers(TRUE, 0);
  1155.           ExitCleanup();    /* cleanup work files */
  1156.           return(1);
  1157.         }
  1158.       break;
  1159.       
  1160.     case WM_CLOSE:
  1161.       ExtendedFunction(function_name(quit));
  1162.       break;
  1163.       
  1164.     default:
  1165.       return (DefWindowProc(hWnd, message, wParam, lParam));
  1166.     }
  1167.   return (NULL);
  1168. }
  1169.  
  1170. /* find row col from pos
  1171.  */
  1172. void GetRowCol(int *prow, int *pcol, int x, int y)
  1173. {
  1174.   register int row, col;
  1175.   
  1176.   col = (x + 1)/g_nCharWidth;
  1177.   row = (y + 1)/g_nLineHeight;
  1178.   
  1179.   if (col < 0)
  1180.     col = 0;
  1181.   else if (col > ncol)
  1182.     col = ncol;
  1183.   if (row < 0)
  1184.     row = 0;
  1185.   else if (row > nrow)
  1186.     row = nrow;
  1187.   
  1188.   *pcol = col;
  1189.   *prow = row;
  1190. }
  1191.  
  1192. /* add things to system menu
  1193.  */
  1194. static void WindowAddMenu(void)
  1195. {
  1196.   HMENU sysmenu = (HMENU) 0;
  1197.   HMENU pop;
  1198.  
  1199.   /* return Window's default menu
  1200.    */
  1201.   if (!(sysmenu = GetSystemMenu(g_hWnd, FALSE)))
  1202.     {
  1203.       WindowMessage("Can't add to system menu!", FALSE);
  1204.       return;
  1205.     }
  1206.   AppendMenu(sysmenu, MF_SEPARATOR, 0, 0L);
  1207.   AppendMenu(sysmenu, MF_STRING, TOGGLE_CHOICE, "Window Men&u");
  1208.   AppendMenu(sysmenu, MF_STRING, FONT_CHOICE, "&Font...");
  1209.  
  1210.   /* Choice + pullright
  1211.   */
  1212.   pop = CreateMenu();        
  1213.   AppendMenu(sysmenu, MF_ENABLED|MF_POPUP, (UINT)pop, "C&olors");
  1214.   AppendMenu(pop, MF_STRING, TCOLOR_CHOICE, "&Text Color...");
  1215.   AppendMenu(pop, MF_STRING, CCOLOR_CHOICE, "T&ouched Text Color...");
  1216.   AppendMenu(pop, MF_STRING, WCOLOR_CHOICE, "&Window Color...");
  1217.  
  1218.   AppendMenu(sysmenu, MF_STRING, SAVE_CHOICE, "&Save Settings");
  1219.   AppendMenu(sysmenu, MF_SEPARATOR, 0, 0L);
  1220.   AppendMenu(sysmenu, MF_STRING, ABOUT_CHOICE, "&About...");
  1221.   AppendMenu(sysmenu, MF_STRING, ABORT_CHOICE, "Shoot Me &Dead!");
  1222. }
  1223. /* Draw cursor; s_cur_* set on draw, used on un-draw.
  1224.  * Needed because ttmove moves g_caret_* w/o turning
  1225.  * off caret.
  1226.  */
  1227. static int s_cur_x, s_cur_y;
  1228. void DoShowCaret(HANDLE hwnd)
  1229. {
  1230.   MakeCaretVis(TRUE);
  1231.   s_cur_x = g_caret_x;
  1232.   s_cur_y = g_caret_y;
  1233. #ifdef WINDOWS_CURSOR
  1234.   ShowCaret(hwnd);
  1235. #else
  1236.   ReverseCaret();
  1237. #endif
  1238. }
  1239. /* Erase cursor
  1240.  */
  1241. void DoHideCaret(HANDLE hwnd)
  1242. {
  1243.   MakeCaretVis(FALSE);
  1244. #ifdef WINDOWS_CURSOR
  1245.   HideCaret(hwnd);
  1246. #else
  1247.   ReverseCaret();
  1248. #endif
  1249. }
  1250. /* Cursor engine stuff if non-windows caret
  1251.  */
  1252. static void ReverseCaret()
  1253. {
  1254.   RECT rect;
  1255.   
  1256.   rect.left = s_cur_x;
  1257.   rect.top = s_cur_y;
  1258.   rect.bottom = rect.top + g_nLineHeight;
  1259.   rect.right = rect.left + g_nCharWidth;
  1260.   InvertRect(g_hDC, &rect);
  1261. }
  1262.  
  1263. /* Manage pointer switching for some operations
  1264.  */
  1265. void WindowSizeCursor(void)
  1266. {
  1267.   HCURSOR cursor = LoadCursor(NULL, IDC_SIZENS);
  1268.   
  1269.   if (cursor)
  1270.     SetCursor(cursor);
  1271. }
  1272. void WindowDragCursor(void)
  1273. {
  1274.   HCURSOR cursor = LoadCursor(NULL, IDC_IBEAM);
  1275.   
  1276.   if (cursor)
  1277.     SetCursor(cursor);
  1278. }
  1279. void WindowArrowCursor(void)
  1280. {
  1281.   FreeLoadedCursor(s_loadedcursor);
  1282.   s_loadedcursor = LoadCursor(g_hInstance, "ID_HANDE");
  1283.   if (s_loadedcursor)
  1284.     SetCursor(s_loadedcursor);
  1285.   else
  1286.     ewprintf("Can't load hand cursor.");
  1287. }
  1288. void WindowSleepCursor(void)
  1289. {
  1290.   HCURSOR cursor = LoadCursor(NULL, IDC_WAIT);
  1291.   
  1292.   if (cursor)
  1293.     SetCursor(cursor);
  1294. }
  1295. #ifdef DOGRINDER
  1296. void WindowGrinderCursor(void)
  1297. {
  1298.   char buff[100];
  1299.   static firstfailure = TRUE;
  1300.   HCURSOR saved = s_loadedcursor;
  1301.  
  1302.   s_sleep++;                /* check for wrap */
  1303.   if (s_sleep > 8)            /* hard coded numbers, ick! */
  1304.     s_sleep = 1;
  1305.  
  1306.   sprintf(buff, "ID_GRINDER%d", s_sleep);
  1307.   s_loadedcursor = LoadCursor(g_hInstance, buff);
  1308.  
  1309.   if (s_loadedcursor)
  1310.     SetCursor(s_loadedcursor);
  1311.   else
  1312.     {
  1313.       if (firstfailure)
  1314.         ewprintf("Can't load sleep cursor");
  1315.       firstfailure = FALSE;
  1316.     }
  1317.   FreeLoadedCursor(saved);
  1318. }
  1319. #endif
  1320. void WindowNormalCursor(void)
  1321. {
  1322.   HCURSOR cursor = LoadCursor(NULL, IDC_ARROW); 
  1323.   
  1324.   if (cursor)
  1325.     {
  1326.       SetCursor(cursor);
  1327.  
  1328.       /* check for old special cursor lying around
  1329.       */
  1330.       FreeLoadedCursor(s_loadedcursor);
  1331.       }
  1332.   s_sleep = 0;
  1333. }
  1334. #ifndef WIN32
  1335. /* Used to find the shell window created when
  1336. * a background job was spawned. On NT, use the
  1337. * real process id
  1338. */
  1339. BOOL FAR PASCAL findWindow(HWND hWnd, LONG lParam)
  1340. {
  1341.   if (GetWindowInstance(hWnd) == (HINSTANCE)lParam) 
  1342.     {
  1343.       s_appwindow = hWnd;
  1344.       return FALSE;   /* found it, stop enumerating */
  1345.     }
  1346.   return TRUE;
  1347. #endif
  1348.  
  1349. /* toggle existance of application menu bar
  1350. */
  1351. int togglemenu(int f, int n)
  1352. {
  1353.   g_menu = (g_menu ? FALSE: TRUE);
  1354.   DoMenuThing();
  1355.   return TRUE;
  1356. }
  1357. /* This is the application window menubar - as opposed
  1358. * to the system menu on the window
  1359. */
  1360. static void DoMenuThing()
  1361. {
  1362.   /* normal app menu?
  1363.   */
  1364.   if (!g_menu)
  1365.     SetMenu(g_hWnd, 0);
  1366.   else if (g_menu)
  1367.     {
  1368.       if (s_menu[PARENT] == (HMENU)0)
  1369.         {
  1370.           HMENU pop;
  1371.  
  1372.           s_choices = KEXTEND_CHOICE;
  1373.  
  1374.           /* FILE (note open commands unique id)
  1375.           */
  1376.           s_menu[PARENT] = CreateMenu();        
  1377.           pop = s_menu[FILEM] = CreatePopupMenu();
  1378.           AppendMenu(pop, MF_STRING, OPEN_CHOICE, function_name(filevisit));
  1379.           AppendMenu(pop, MF_STRING, OPEN_CHOICE2, function_name(poptofile));
  1380.           AppendMenu(pop, MF_STRING, INSERT_CHOICE, function_name(fileinsert));
  1381.           AppendMenu(pop, MF_STRING, s_choices++, function_name(filesave));
  1382.           AppendMenu(pop, MF_STRING, SAVEAS_CHOICE, function_name(filewrite));
  1383.           AppendMenu(pop, MF_STRING, s_choices++, function_name(savebuffers));
  1384.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1385.           AppendMenu(pop, MF_STRING, REVERT_CHOICE, function_name(reverto));
  1386.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1387.           AppendMenu(pop, MF_STRING, s_choices++, function_name(quit));
  1388. #ifdef DOPRINT
  1389.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1390.           AppendMenu(pop, MF_STRING, PRINT_CHOICE, (LPCSTR)"Print...");
  1391. #endif
  1392.           AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, 
  1393.                      (UINT)pop, (LPCSTR)"File");
  1394.  
  1395.           /* EDIT
  1396.           */
  1397.           pop = s_menu[EDITM]= CreatePopupMenu();
  1398.           AppendMenu(pop, MF_STRING, s_choices++, function_name(forwsearch));
  1399.           AppendMenu(pop, MF_STRING, s_choices++, function_name(backsearch));
  1400.           AppendMenu(pop, MF_STRING, s_choices++, function_name(queryrepl));
  1401.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1402.           AppendMenu(pop, MF_STRING, s_choices++, function_name(setmark));
  1403.           AppendMenu(pop, MF_STRING, s_choices++, function_name(swapmark));
  1404.           AppendMenu(pop, MF_STRING, s_choices++, function_name(killregion));
  1405.           AppendMenu(pop, MF_STRING, s_choices++, function_name(copyregion));
  1406.           AppendMenu(pop, MF_STRING, s_choices++, function_name(yank));
  1407.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1408.           AppendMenu(pop, MF_STRING, s_choices++, function_name(definemacro));
  1409.           AppendMenu(pop, MF_STRING, s_choices++, function_name(finishmacro));
  1410.           AppendMenu(pop, MF_STRING, s_choices++, function_name(executemacro));
  1411.           AppendMenu(pop, MF_STRING, s_choices++, function_name(extend));
  1412.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1413.           AppendMenu(pop, MF_STRING, CUT_CHOICE, (LPCSTR)"Cut Region");
  1414.           AppendMenu(pop, MF_STRING, COPY_CHOICE, (LPCSTR)"Copy Region");
  1415.           AppendMenu(pop, MF_STRING, PASTE_CHOICE, (LPCSTR)"Paste");
  1416.  
  1417.           AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, 
  1418.                      (UINT)pop, (LPCSTR)"Edit");
  1419.  
  1420.           /* WINDOW
  1421.           */
  1422.           pop = s_menu[WINDOWM] = CreatePopupMenu();
  1423.           AppendMenu(pop, MF_STRING, s_choices++, function_name(usebuffer));
  1424.           AppendMenu(pop, MF_STRING, s_choices++, function_name(killbuffer));
  1425.           AppendMenu(pop, MF_STRING, s_choices++, function_name(listbuffers));
  1426.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1427.           AppendMenu(pop, MF_STRING, s_choices++, function_name(nextwind));
  1428.           AppendMenu(pop, MF_STRING, s_choices++, function_name(prevwind));
  1429.           AppendMenu(pop, MF_STRING, s_choices++, function_name(splitwind));
  1430.           AppendMenu(pop, MF_STRING, s_choices++, function_name(onlywind));
  1431.  
  1432.           AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, (UINT)pop, 
  1433.                      (LPCSTR)"Window");
  1434.           
  1435.           /* EXEC
  1436.           */
  1437.           pop = s_menu[EXECM] = CreatePopupMenu();
  1438.           AppendMenu(pop, MF_STRING, s_choices++, function_name(windowprog));
  1439.           AppendMenu(pop, MF_STRING, s_choices++, function_name(spawncli2));
  1440.           AppendMenu(pop, MF_STRING, s_choices++, function_name(spawncli));
  1441.           AppendMenu(pop, MF_SEPARATOR, 0, 0L);
  1442.           AppendMenu(pop, MF_STRING, s_choices++, function_name(sysmake));
  1443.           AppendMenu(pop, MF_STRING, s_choices++, function_name(makeerror));
  1444.  
  1445.           AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, (UINT)pop, 
  1446.                      "Execute");
  1447.  
  1448.           /* HELP
  1449.           */
  1450.           pop = s_menu[HELPM] = CreatePopupMenu();
  1451.           AppendMenu(pop, MF_STRING, HELP_APROPOS, 
  1452.                      function_name(apropos_command));
  1453.           AppendMenu(pop, MF_STRING, HELP_ABOUT, "about...");
  1454.  
  1455.           AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, (UINT)pop, 
  1456.                      (LPCSTR)"Help");
  1457.         }
  1458.       SetMenu(g_hWnd, s_menu[PARENT]);
  1459.     }
  1460.   DrawMenuBar(g_hWnd);
  1461. }
  1462. static void chooseColor(wParam)
  1463. WPARAM wParam;
  1464. {
  1465.   CHOOSECOLOR colors;
  1466.   COLORREF extra[16];
  1467.   BOOL s;
  1468.  
  1469.   /* Use special common dialog for chosing color. Note
  1470.   * that I didn't feel like doing the work of managing
  1471.   * special mixed colors; you get the ones windows gives
  1472.   * you. Note also that you can choose non-pure colors
  1473.   * and on displays with limited colors, it looks crummy
  1474.   */
  1475.   memset(&colors, 0, sizeof(colors));
  1476.   colors.lStructSize = sizeof(CHOOSECOLOR);
  1477.   colors.hwndOwner = g_hWnd;
  1478.   colors.rgbResult = (wParam == TCOLOR_CHOICE ?
  1479.                       GetForeColor() : (wParam == CCOLOR_CHOICE ?
  1480.                                         GetHighColor() : GetBackColor()));
  1481.  
  1482.   colors.Flags |= CC_RGBINIT | CC_PREVENTFULLOPEN;
  1483.   colors.lpCustColors = extra;    /* Crash if this is NULL, even
  1484.                                  * though the flag does not say to use
  1485.                                  * them. Bogus that it is required.. */
  1486.  
  1487.   EnableWindow(g_hWnd, FALSE);
  1488.   s = ChooseColor(&colors);
  1489.   EnableWindow(g_hWnd, TRUE);
  1490.   SetActiveWindow(g_hWnd);
  1491.  
  1492.   if (s)
  1493.     {
  1494.       if (wParam == TCOLOR_CHOICE)
  1495.         SetForeColor(colors.rgbResult);
  1496.       else if (wParam == WCOLOR_CHOICE)
  1497.         SetBackColor(colors.rgbResult);
  1498.       else if (wParam == CCOLOR_CHOICE)
  1499.         SetHighColor(colors.rgbResult);
  1500.       ExtendedFunction(function_name(myrefresh));              
  1501.     }
  1502. }
  1503.  
  1504. /* Wrappers to get to support from menu
  1505. */
  1506. int NewFont(f, n)
  1507. int f, n;
  1508. {
  1509.   WindowNewFont();
  1510.   return(TRUE);
  1511. }
  1512. int NewTextColor(f, n)
  1513. int f, n;
  1514. {
  1515.   chooseColor(TCOLOR_CHOICE);
  1516.   return(TRUE);
  1517. }
  1518. int NewTouchedTextColor(f, n)
  1519. int f, n;
  1520. {
  1521.   chooseColor(CCOLOR_CHOICE);
  1522.   return(TRUE);
  1523. }
  1524. int NewWindowColor(f, n)
  1525. int f, n;
  1526. {
  1527.   chooseColor(WCOLOR_CHOICE);
  1528.   return(TRUE);
  1529. }
  1530. #endif /** JAM **/
  1531.